package com.sugon.controller.device;


import cn.afterturn.easypoi.entity.vo.TemplateExcelConstants;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.view.PoiBaseView;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.sugon.annotation.DataFilter;
import com.sugon.annotation.NonBusinessParamValid;
import com.sugon.dao.DeviceInfoDao;
import com.sugon.entity.*;
import com.sugon.modules.alarm.service.AlarmCodeBaseService;
import com.sugon.modules.analyse.model.vo.DeviceVO;
import com.sugon.modules.device.model.vo.DeviceApproveParamVO;
import com.sugon.modules.device.model.vo.ExceptionUploadParam;
import com.sugon.modules.device.service.IDeviceManager;
import com.sugon.modules.todo.consts.TodoSource;
import com.sugon.modules.todo.consts.TodoStatus;
import com.sugon.service.*;
import com.sugon.utils.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.util.*;

/**
 * 设备信息Controller
 *
 * @author sugon
 * @date 2019-07-15 08:37:25
 */
@Controller
@RequestMapping("deviceinfo")
public class DeviceInfoController {

    @Resource
    private DeviceInfoService deviceService;
    @Resource
    private DeviceInfoDao deviceInfoDao;
    @Resource
    private IDeviceManager deviceManager;
    @Resource
    private SysConfigService configService;
    @Resource
    private DevMaintenPlanService devPmRuleService;
    @Resource
    private DevRepairRecordService devRepairRecordService;
    @Resource
    private AlarmCodeBaseService alarmCodeBaseService;
    @Resource
    private DevMaintenanceTicketService devPmTicketService;
    @Resource
    private DevMaintenanceTicketService pmTicketService;
    @Resource
    private DevAmTicketService amTicketService;
    @Resource
    private ErmsTodoListService todoListService;
    @Resource
    private InspectionRecordingJoinService inspectService;
    @Resource
    private FactoryTypeService factoryTypeService;

    /**
     * 异常上报API，目前主要适用于设备维修或者维护中的异常上报
     *
     * @param exceptionUploadParam
     * @param bindingResult
     * @return
     */
    @ResponseBody
    @NonBusinessParamValid
    @PostMapping("/uploadException")
    public R uploadException(@RequestBody @Validated ExceptionUploadParam exceptionUploadParam, BindingResult bindingResult) {
        String devId;
        // 判定是否是支持的异常上报类型
        TodoSource todoSource = TodoSource.getInstanceByValue(exceptionUploadParam.getSource());
        if (todoSource == null) {
            return R.error("暂不支持该来源的异常上报！");
        }
        if (TodoSource.REPAIR == todoSource) {
            DevRepairRecordEntity repairRecord = devRepairRecordService.queryObject(exceptionUploadParam.getOriginRecordId());
            if (repairRecord == null) {
                return R.error("维修工单不存在，请确认！");
            }
            devId = repairRecord.getDevId();
        } else if (TodoSource.PM == todoSource) {
            DevMaintenanceTicketEntity pmTicket = pmTicketService.queryObject(exceptionUploadParam.getOriginRecordId());
            if (pmTicket == null) {
                return R.error("预防维护工单不存在，请确认！");
            }
            devId = pmTicket.getDevId();
        } else if (TodoSource.AM == todoSource) {
            DevAmTicketEntity amTicket = amTicketService.queryObject(exceptionUploadParam.getOriginRecordId());
            if (amTicket == null) {
                return R.error("自主维护工单不存在，请确认！");
            }
            devId = amTicket.getDevId();
        } else if (TodoSource.INSPECT == todoSource) {
            InspectionRecordingJoinEntity inspectRecord = inspectService.queryObject(exceptionUploadParam.getOriginRecordId());
            if (inspectRecord == null) {
                return R.error("设备巡检记录不存在，请确认！");
            }
            devId = inspectRecord.getDevId();
        } else if (TodoSource.FAULT_ANALYSE == todoSource) {
            DevRepairRecordEntity repairRecord = devRepairRecordService.queryObject(exceptionUploadParam.getOriginRecordId());
            if (repairRecord == null) {
                return R.error("维修工单不存在，请确认！");
            }
            devId = repairRecord.getDevId();
        } else {
            return R.error("暂不支持该来源的异常上报！");
        }

        DeviceInfoEntity device = deviceService.queryObject(devId);
        Assert.notNull(device);
        // 保存异常记录信息
        ErmsTodoList todoItem = new ErmsTodoList();
        CopyOptions copyOptions = CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true);
        BeanUtil.copyProperties(exceptionUploadParam, todoItem, copyOptions);
        todoItem.setDevId(devId);
        todoItem.setExType(todoSource.getExType());
        todoItem.setWorkshopId(StrUtil.sub(device.getDeptCode(), 0, 4));
        todoItem.setStatus(TodoStatus.UN);
        return todoListService.save(todoItem) > 0 ? R.ok() : R.error();
    }

    /**
     * 查询设备关联统计数据，关联数据包括：维修记录、维护工单 、报警代码库、维护规程
     *
     * @param devId 设备ID
     * @return
     */
    @GetMapping("/loadDevAssociationStat")
    @ResponseBody
    public R loadDevAssociationStat(@RequestParam String devId) {
        // 校验设备是否存在
        DeviceInfoEntity device = deviceService.queryObject(devId);
        if (device == null) {
            return R.error("设备不存在，请确认！");
        }
        List<String> associationStatList = CollectionUtil.newArrayList();
        // 报警代码库
        List<AlarmCodeBaseEntity> alarmCodeBaseList = alarmCodeBaseService.queryList(null, devId, null);
        if (CollectionUtil.isNotEmpty(alarmCodeBaseList)) {
            associationStatList.add(StrUtil.format("{}条设备报警代码库配置", alarmCodeBaseList.size()));
        }
        // 设备维修记录
        List<DevRepairRecordEntity> repairRecordList = devRepairRecordService.queryListByDevId(devId);
        if (CollectionUtil.isNotEmpty(repairRecordList)) {
            associationStatList.add(StrUtil.format("{}条设备维修记录", repairRecordList.size()));
        }
        // 维护工单数
        List<DevMaintenanceTicketEntity> pmTicketList = devPmTicketService.queryListByDevId(devId);
        if (CollectionUtil.isNotEmpty(pmTicketList)) {
            associationStatList.add(StrUtil.format("{}个设备维护工单", pmTicketList.size()));
        }
        // 维护规程
        List<DevMaintenPlanEntity> pmRuleList = devPmRuleService.list(devId, null, null);
        if (CollectionUtil.isNotEmpty(pmRuleList)) {
            associationStatList.add(StrUtil.format("{}条设备预防维护规程", pmRuleList.size()));
        }
        return R.ok(CollectionUtil.join(associationStatList, ","));
    }

    /**
     * 获取设备铭牌
     *
     * @param devId 设备ID
     * @return
     */
    @RequestMapping("/loadDevNameplate")
    @ResponseBody
    public R loadDevNameplate(@RequestParam String devId, String isReset) {
        // 校验设备是否存在
        DeviceInfoEntity device = deviceService.queryObject(devId);
        if (device == null) {
            return R.error("设备不存在，请确认！");
        }
        // 如果铭牌不为空，则直接返回
        String nameplate;
        if (StrUtil.isNotEmpty(isReset)) {
            nameplate = deviceService.generateNameplate(device);
            device.setNameplate(nameplate);
            deviceService.update(device);
        } else {
            nameplate = device.getNameplate();
            if (StrUtil.isEmpty(nameplate)) {
                nameplate = deviceService.generateNameplate(device);
                device.setNameplate(nameplate);
                deviceService.update(device);
            }
        }
        return R.ok().put("nameplateUrl", nameplate);
    }

    /**
     * 获取设备铭牌
     *
     * @param devId 设备ID
     * @return
     */
    @RequestMapping("/loadFixedAssets")
    @ResponseBody
    public R loadFixedAssets(@RequestParam String devId) {
        // 校验设备是否存在
        DeviceInfoEntity device = deviceService.queryObject(devId);
        if (device == null) {
            return R.error("设备不存在，请确认！");
        }
        // 校验是否设置固资编码
        if (StrUtil.isEmpty(device.getFirmNo())) {
            return R.error("该设备未设置固资编码，无法进一步查看固资详情！");
        }
        // 校验是否有匹配的固资记录
        List<FixedAssets> fixedAssetsList = deviceInfoDao.queryByFirmNo(device.getFirmNo());
        if (CollectionUtil.isEmpty(fixedAssetsList)) {
            return R.error("根据设置的固资编码未查询到匹配的固资记录，请确认是否配置正确或数据已同步成功！");
        }
        return R.ok().put("data", fixedAssetsList.get(0));
    }

    /**
     * 根据工序号加载该工序的设备列表
     */
    @RequestMapping("/loadProcessDev")
    @ResponseBody
    public R loadProcessDev(@RequestParam String devProductCode, @RequestParam String devProceNo) {
        Map<String, Object> params = new HashMap<>();
        params.put("devProductName", devProductCode);
        params.put("devProceName", devProceNo);
        List<DeviceInfoEntity> deviceInfoList = deviceService.queryList(params);
        if (deviceInfoList == null) {
            deviceInfoList = new ArrayList<>();
        }
        return R.ok().put("deviceInfoList", deviceInfoList);
    }

    /**
     * 查看列表
     */
    @RequestMapping("/list")
//    @RequiresPermissions("deviceinfo:list")
    @ResponseBody
    public R list(@RequestParam Map<String, Object> params) {
        params.put("delFlag", "1");
        //查询列表数据
        Query query = new Query(params);

        List<DeviceInfoEntity> deviceInfoList = deviceService.queryList(query);
        int total = deviceService.queryTotal(query);

        PageUtils pageUtil = new PageUtils(deviceInfoList, total, query.getLimit(), query.getPage());

        return R.ok().put("page", pageUtil);
    }

    /**
     * 查看 已/未 编制计划的设备列表
     */
    @DataFilter(deptAlias = "DEV_FARM", userAlias = "CREATE_USER")
    @RequestMapping("/listPlanRelated")
    @ResponseBody
    public R listPlanRelated(@RequestParam Map<String, Object> params) {
        //查询列表数据
        Query query = new Query(params);
        List<DeviceInfoEntity> deviceInfoList = deviceInfoDao.listPlanRelated(query);
        int total = deviceInfoDao.listPlanRelatedTotal(query);
        PageUtils pageUtil = new PageUtils(deviceInfoList, total, query.getLimit(), query.getPage());
        return R.ok().put("page", pageUtil);
    }

    /**
     * 查看信息
     */
    @RequestMapping("/info/{id}")
//    @RequiresPermissions("deviceinfo:info")
    @ResponseBody
    public R info(@PathVariable("id") String id) {
        DeviceInfoEntity deviceInfo = deviceService.queryObject(id);

        return R.ok().put("deviceInfo", deviceInfo);
    }

    /**
     * 查看信息bydevCode
     */
    @RequestMapping("/getInfoByDevCode/{devCode}")
    @ResponseBody
    public R getInfoByDevCode(@PathVariable("devCode") String devCode) {
        DeviceInfoEntity deviceInfo = deviceService.getInfoByDevCode(devCode);

        return R.ok().put("deviceInfo", deviceInfo);
    }

    /**
     * 所有信息
     */
    @RequestMapping("/deviceInfoAll")
    @ResponseBody
    public R deviceInfoAll() {
        List<Map<String, Object>> list = deviceService.deviceInfoAll();
        return R.ok().put("list", list);
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    @RequiresPermissions("deviceinfo:save")
    @ResponseBody
    public R save(@RequestBody DeviceInfoEntity deviceInfo) {
        // 重新设置下供应厂商编码
        if (StrUtil.isNotEmpty(deviceInfo.getSupplierId())) {
            FactoryTypeEntity factoryType = factoryTypeService.queryObject(deviceInfo.getSupplierId());
            if (factoryType != null) {
                deviceInfo.setDevSupply(factoryType.getFaCode());
            }
        }
        //设备状态 完好再用
        deviceInfo.setDevStatus("1");
        deviceService.save(deviceInfo);
        return R.ok().put("id", deviceInfo.getId());
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    @RequiresPermissions("deviceinfo:update")
    @ResponseBody
    public R update(@RequestBody DeviceInfoEntity deviceInfo) {
        // 重新设置下供应厂商编码
        if (StrUtil.isNotEmpty(deviceInfo.getSupplierId())) {
            FactoryTypeEntity factoryType = factoryTypeService.queryObject(deviceInfo.getSupplierId());
            if (factoryType != null) {
                deviceInfo.setDevSupply(factoryType.getFaCode());
            }
        }
        return deviceService.update(deviceInfo) > 0 ? R.ok() : R.error();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    @RequiresPermissions("deviceinfo:delete")
    @ResponseBody
    public R delete(@RequestBody String[] ids) {
        deviceService.deleteBatch(ids);

        return R.ok();
    }

    /**
     * 查看所有列表
     */
    @RequestMapping("/queryAll")
    @ResponseBody
    public R queryAll(@RequestParam Map<String, Object> params) {

        List<DeviceInfoEntity> list = deviceService.queryList(params);

        return R.ok().put("list", list);
    }

    /**
     * 根据大类code获取条数
     */
    @RequestMapping("/countByDevTypeB")
    @ResponseBody
    public R countByDevTypeB(@RequestParam Map<String, Object> params) {
        int total = deviceService.queryTotal(params);
        return R.ok().put("total", total);
    }

    /**
     * 导出二维码
     */
    @RequestMapping("/export")
    @ResponseBody
    public R export(HttpServletResponse response, @RequestParam Map<String, Object> params) {
        QRcodePOI poi = new QRcodePOI();
        List<DeviceInfoEntity> list = deviceService.queryList(params);
        poi.export(response, list);
        return R.ok();
    }

    /**
     * 导出二维码
     */
    @RequestMapping("/generateQrCode")
    @ResponseBody
    public R generateQrCode(@RequestParam Map<String, Object> params) {
        List<DeviceInfoEntity> list = deviceService.queryList(params);
//        PrintImage.generateDevicePostcard(list);
        return R.ok().put("message", "成功生成" + list.size() + "条设备二维码信息");
    }

    /**
     * 闲置状态--审核
     */
    @RequestMapping("/review")
//    @RequiresPermissions("deviceinfo:review")
    @ResponseBody
    public R review(@RequestBody String id) {
        deviceService.updateView(id);

        return R.ok();
    }

    /**
     * 根据多个id获取数据
     */
    @RequestMapping("/getDevInfoByIds")
    @ResponseBody
    public R getDevInfo(@RequestBody String[] id) {
        List infoList = deviceService.getDevInfo(id);
        return R.ok().put("infoList", infoList);
    }

    /**
     * 设备清单导入
     */
    @RequestMapping("/imports")
    @RequiresPermissions("devfile:imports")
    @ResponseBody
    public R imports(@RequestParam("file") MultipartFile file) throws Exception {
        int num = deviceService.imports(file);
        return R.ok("成功导入" + num + "记录");
    }

    @RequestMapping("/exportData")
    @RequiresPermissions("devfile:imports")
    @ResponseBody
    public void export(@RequestParam Map<String, Object> params, ModelMap modelMap, HttpServletRequest request, HttpServletResponse response) throws FileNotFoundException {
        // 移除空值参数
        MapUtil.removeEmptyValue(params);
        TemplateExportParams templateExportParams = new TemplateExportParams(configService.getPoiTemplatePath() + "deviceIETemplate.xlsx");
        modelMap.put(TemplateExcelConstants.FILE_NAME, "设备信息导出_" + com.sugon.modules.utils.DateUtil.today());
        modelMap.put(TemplateExcelConstants.PARAMS, templateExportParams);
        modelMap.put(TemplateExcelConstants.MAP_DATA, deviceService.prepareExportData(params));
        PoiBaseView.render(modelMap, request, response, TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);
    }

    /**
     * 审核
     */
    @RequestMapping("/check")
    @RequiresPermissions("deviceinfo:check")
    @ResponseBody
    public R check(@RequestBody String id) {
        deviceService.check(id);
        return R.ok();
    }

    @NonBusinessParamValid
    @RequiresPermissions("deviceinfo:check")
    @RequestMapping("/Approval")
    @ResponseBody
    public R approval(@Validated @RequestBody DeviceApproveParamVO sparePart, BindingResult bindingResult) {
        return deviceManager.batchApprove(sparePart) ? R.ok() : R.error();
    }

    /**
     * 根据工序号获取该工序下关联的设备列表
     */
    @RequestMapping("/getByStationCode")
    @ResponseBody
    public R getByStationCode(@RequestParam("deptCode") String deptCode) {
        List<DeviceVO> deviceList = deviceInfoDao.queryStationDev(deptCode);
        return R.ok().put("deviceList", Optional.ofNullable(deviceList).orElse(CollectionUtil.newArrayList()));
    }

}
